from symbide.src.parsing import PATTERN, parsers
from symbide import OPTIONS
from xml.sax.saxutils import escape, unescape

def parse(text):
    '''
    Carries out the parsing from plain sympy code to executeable code.
    
    This process is structured as follows:
        - escape all strings, so they won't be deformed by further parsing
        - encapsulate all numbers with sympy.Number
        - split text up in single statements
        - define before each statement all not yet declared keywords
        - unescape all strings again
    '''
    
    text = text.expandtabs(int(OPTIONS['tabswidth']))
    
    text = parsers['string'].escape(text)
    
    statements = parsers['statement'].parse(text)
    
    buf = []
    for statement in statements:
        possibleVariables = PATTERN['variable'].findall(statement[1])
        indent = _getIndent(''.join(statement))
        vardef = ' '*indent+'__defineVariables__(*%s)'
        buf.append(vardef%possibleVariables)
        if statement[0]:
            if PATTERN['function'].findall(statement[0]):
                p1 = statement[0].find('(')
                p2 = statement[0].rfind(')')
                vars = statement[0][p1+1:p2].replace(',','","')
                expr = parsers['number'].parse(statement[1])
                text = '%s = easyFunction("%s","%s")'%(statement[0][:p1],vars,expr)
                buf.append(text)
            else:
                buf.append('='.join(statement))
        else:
            buf.append(statement[1])
    text = parsers['number'].parse('\n'.join(buf))
    text = text.replace(' <ind>','').replace('</ind>', '').replace('<parser off>', '').replace('<parser on>', '')
    text = parsers['string'].unescape(text)
    return text
    
def _getIndent(text):
    '''
    Returns the count of whitespaces (after converting tabs) at the 
    beginning of text.
    '''
    
    i = 0
    for char in text:
        if char!=' ':
            break
        i+=1
    return i